package com.legendframework.core.dao.extension.service;

import com.legendframework.core.dao.DefaultEntityValue;
import com.legendframework.core.dao.annotation.Transactional;
import com.legendframework.core.ioc.annotation.Resource;
import com.legendframework.core.dao.DataResources;
import com.legendframework.core.dao.EntityDaoGenerate;
import com.legendframework.core.dao.IDao;
import com.legendframework.core.dao.exception.ServiceException;
import com.legendframework.core.dao.page.Page;
import com.legendframework.core.dao.transaction.JdbcTransaction;
import com.legendframework.core.dao.transaction.YamlTransaction;
import com.legendframework.core.dao.wrapper.Wrapper;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class BaseService<T,D extends IDao<T>> implements IService<T> {

    @Resource(required = false)
    private D entityDao;

    /**
     * 构建实体类Dao层对象
     * @param dataResources Dao所必须的数据包
     * @param iocHandle IOC容器处理器，预期是需要外层IOC提供实现方法对Dao实现类进行动态代理
     * @return
     */
    private void generateEntityDao(DataResources dataResources , Function<Object,Object> iocHandle , JdbcTransaction jdbcTransaction , YamlTransaction yamlTransaction){
        Class<D> entityDaoClass = null;
        //获取参数 'D' 的字节码
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        if(IService.class.isAssignableFrom(((ParameterizedTypeImpl) genericSuperclass).getRawType()) && ((ParameterizedType) genericSuperclass).getActualTypeArguments().length == 1){
            entityDaoClass = (Class) ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
            entityDao = (D) EntityDaoGenerate.getDaoByEntityType(entityDaoClass, dataResources,iocHandle,jdbcTransaction,yamlTransaction);
            return;
        }
    }

    /**
     * 获取Dao层接口
     * @return
     */
    protected D getEntityDao(){
        if (entityDao == null) {
            throw new ServiceException(String.format("类[ %s ], entityDao实例化失败",this.getClass().getName()));
        }
        return entityDao;
    }

    @Override
    public boolean save(T entity) {
        return getEntityDao().insert(entity) > 0;
    }

    @Override
    public synchronized boolean saveDefault(Serializable id) {
        T entity = getById(id);
        if (entity == null) {
            entity = DefaultEntityValue.getEntity(entityDao.getEntityClass(), id);
            return save(entity);
        }
        return false;
    }

    @Override
    public boolean removeById(Serializable id) {
        return getEntityDao().deleteById(id) > 0;
    }

    @Override
    public boolean remove(Wrapper<T> queryWrapper) {
        return getEntityDao().delete(queryWrapper) > 0;
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        return getEntityDao().deleteBatchIds(idList) > 0;
    }

    @Override
    public boolean updateById(T entity) {
        return getEntityDao().updateById(entity) > 0;
    }

    @Override
    public boolean update(T entity, Wrapper<T> updateWrapper) {
        return getEntityDao().update(entity,updateWrapper) > 0;
    }

    @Override
    public T getById(Serializable id) {
        return getEntityDao().selectById(id);
    }

    @Override
    public List<T> listByIds(Collection<? extends Serializable> idList) {
        return getEntityDao().selectBatchIds(idList);
    }

    @Override
    public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
        return getEntityDao().selectOne(queryWrapper,throwEx);
    }

    @Override
    public Object getObj(Wrapper<T> queryWrapper) {
        return getOne(queryWrapper);
    }

    @Override
    public long count(Wrapper<T> queryWrapper) {
        return getEntityDao().selectCount(queryWrapper);
    }

    @Override
    public List<T> list(Wrapper<T> queryWrapper) {
        return getEntityDao().selectList(queryWrapper);
    }

    @Override
    public Page<T> page(Page<T> page, Wrapper<T> queryWrapper) {
        return getEntityDao().selectPage(page,queryWrapper);
    }

    @Override
    public List<Object> listObjs(Wrapper<T> queryWrapper) {
        return list(queryWrapper).stream().map(item -> (Object) item).collect(Collectors.toList());
    }

    @Override
    public T getOne() {
        return getEntityDao().getOne();
    }

    @Override
    @Transactional
    public void reload() {
        getEntityDao().reload();
    }
}
